// f[i][j] = max(f[i - 1][j], f[i - 1][j - v] + w, f[i - 1][j -2v] + 2w, f[i - 1][j - sv] + sw)
// f[i][j - v] = max(         f[i - 1][j - v],     f[i - 1][j - 2v] + w, f[i - 1][j - sv] + (s - 1)w, f[ i - 1][j - s+1v])
// 可以发现每次要求f[i]的最大值时，都需要前一个f[i]加上偏移量的最大值，也就是说下标越小优势越大
// 发现可以通过余数枚举所有的可能性使用单调队列
// 所以在使用单调队列的时候需要考虑偏移量
// 我们还可以利用滚动数组来优化空间
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 20010;
int f[N], g[N], q[N];
int n, m;

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
    {
        int vi, wi, si;
        cin >> vi >> wi >> si;
        // 使用单调队列之前先用滚动数组保存当前数据
        memcpy(g, f, sizeof f);
        // 枚举所有余数
        for (int j = 0; j < vi; ++j)
        {
            int hh = 0, tt = -1;
            for (int k = j; k <= m; k += vi)
            {
                // 先判断队头是否需要出窗口
                if (tt >= hh && q[hh] < k - si * vi)
                    ++hh;
                // 然后删去比当前值还要小的队列元素
                // 判断的方式是队尾值减去下标的偏移量更大
                while (tt >= hh && g[q[tt]] - (q[tt] - j) / vi * wi <= g[k] - (k - j) / vi * wi)
                    --tt;
                q[++tt] = k;
                f[k] = max(g[k], g[q[hh]] + (k - q[hh]) / vi * wi);
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}
